﻿/*======================================================================
== Copyright : BlueCurve (c)
== Licence   : Gnu/GPL v2.x
== Author    : Teddy Albina
== Email     : bluecurveteam@gmail.com
== Web site  : http://www.codeplex.com/BlueCurve
========================================================================*/
using System;
using System.AddIn;
using System.Collections.Generic;
using System.IO;
using System.IO.Packaging;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using Common;
using IndexLibrary;

namespace Addins.Ooxml
{
    [AddIn("Addins.Ooxml",
    Version = "1.0.0.0",
    Description = "This addin can index OOXML documents",
    Publisher = "BlueCurve Project Team")]
    public class AddinsOoxml : Plugins.View.AddinsView
    {
        #region 'Configuration'
        
        /// <summary>
        /// Common functions
        /// </summary>
        private CommonFunctions Common = new CommonFunctions();
        /// <summary>
        /// Eventlog library
        /// </summary>
        private EventLogLibrary eventLog = EventLogLibrary.GetInstance();
        /// <summary>
        /// Propriety dictionnary
        /// </summary>
        private Dictionary<string, string> _file = new Dictionary<string, string>();
        /// <summary>
        /// Entities dictionnary
        /// </summary>
        private Dictionary<string, string> entities = new Dictionary<string, string>();
        /// <summary>
        /// Full Text index library
        /// </summary>
        private FullTextIndexLibrary Index = FullTextIndexLibrary.GetInstance();
        /// <summary>
        /// Serialization class
        /// </summary>
        private Serialization serializ = new Serialization();
        /// <summary>
        /// EntityXML data
        /// </summary>
        private string entityXML = "none";
        /// <summary>
        /// The document text
        /// </summary>
        private string documentText = null;

        #endregion






        #region 'Functions'

        /// <summary>
        /// The plugin main function
        /// </summary>
        /// <see cref="http://www.asp-php.net/tutorial/asp.net/openxml.php?page=3"/>
        /// <param name="location">file location</param>
        /// <param name="state">file state</param>
        public override void IndexerLoader(string location, int state)
        {
            try
            {
                if (!File.Exists(location))
                    return;

                bool success = this.GetText(location);

                if (!success)
                    return;
                else
                    documentText = Common.Stripspaces(documentText);

                // Document title
                string documentTitle = this.GetEntity("title", location);
                

                // Document description
                string documentDesciption = this.GetEntity("description", location);


                // File dictionnary proprieties
                _file.Add("path", location);
                _file.Add("title", documentTitle ?? "Untitled document");
                _file.Add("filetype", Common.GetExtension(location));
                _file.Add("filecategory", "Desktop");
                _file.Add("size", Convert.ToString(Common.GetFileLength(location)));
                _file.Add("content", documentText);


                // Retrieve document meta data
                success = this.GetEntity(location);

                if (!success)
                    entities.Clear();

                if (entities.Count > 0)
                {
                    MemoryStream memory = new MemoryStream();
                    StreamWriter writer = new StreamWriter(memory);

                    string entitybuffer = serializ.Serialize(writer, memory, entities);

                    if (entitybuffer != null)
                        entityXML = entitybuffer;

                    memory.Close();
                    writer.Close();
                }



                bool res = true;

                switch (state)
                {
                    case 1:
                        res = Index.AddValue(_file, entities, entityXML);
                        if (res)
                            Console.WriteLine("File " + location + "\n successfully indexed");
                        else
                            Console.WriteLine("Unable to index " + location);
                        break;
                    case 3:
                        res = Index.UpdateValue(_file, entities, entityXML);
                        if (res)
                            Console.WriteLine("File " + location + "\n successfully updated");
                        else
                            Console.WriteLine("Unable to update " + location);
                        break;
                    default:
                        break;
                }
            }
            catch (Exception e)
            {
                eventLog.WritenewEvent(e.ToString());
                Console.WriteLine(e);
            }
        }





        /// <summary>
        /// Retrieve a specific document entity
        /// </summary>
        /// <param name="entity">Entity name</param>
        /// <param name="location">Document location</param>
        /// <returns>string entity</returns>
        private string GetEntity(string entity, string location)
        {
            try
            {
                // Load the OOXML or XPS document
                Package package = Package.Open(location, FileMode.Open, FileAccess.Read);

                PackageRelationshipCollection relcollection = package.GetRelationshipsByType("http://schemas.openxmlformats.org/package/2006/metadata/core-properties");

                IEnumerator<PackageRelationship> relnum = relcollection.GetEnumerator();
                relnum.MoveNext();
                PackageRelationship coreDoc = relnum.Current;

                if (coreDoc != null)
                {
                    PackagePart _part = package.GetPart(PackUriHelper.CreatePartUri(coreDoc.TargetUri));
                    XDocument xmldoc = XDocument.Load(XmlReader.Create(_part.GetStream()));

                    var x = from y in xmldoc.Elements()
                            where y.Name == @"dc:" + entity
                            select y.Value;

                    foreach (var m in x)
                        if (!string.IsNullOrEmpty(m))
                            return m;
                }
                package.Close();
                return null;
            }
            catch (Exception e)
            {
                eventLog.WritenewEvent(e.ToString());
                Console.WriteLine(e);
                return null;
            }
        }



        /// <summary>
        /// Retrieve all document entities
        /// </summary>
        /// <param name="location">document location</param>
        /// <returns>bool</returns>
        private bool GetEntity(string location)
        {
            try
            {
                // Load the OOXML or XPS document
                Package package = Package.Open(location, FileMode.Open, FileAccess.Read);
                
                // Relations collection
                PackageRelationshipCollection relcollection = package.GetRelationshipsByType("http://schemas.openxmlformats.org/package/2006/metadata/core-properties");

                // Relations
                IEnumerator<PackageRelationship> relnum = relcollection.GetEnumerator();
                relnum.MoveNext();

                PackageRelationship coreDoc = relnum.Current;

                if (coreDoc != null)
                {
                    PackagePart _part = package.GetPart(PackUriHelper.CreatePartUri(coreDoc.TargetUri));
                    XDocument xmldoc = XDocument.Load(XmlReader.Create(_part.GetStream()));

                    var x = from y in xmldoc.Elements()
                            select new
                            {
                                Subject = y.Element("dc:subject").Value ?? "none",
                                Creator = y.Element("dc:creator").Value ?? "none",
                                Keywords = y.Element("cp:keywords").Value ?? "none",
                                LastModifiedBy = y.Element("cp:lastModifiedBy").Value ?? "none",
                                Revision = y.Element("cp:revision").Value ?? "none",
                                Created = y.Element("dcterms:created").Value ?? "none",
                                Modified = y.Element("dcterms:modified").Value ?? "none",
                                Category = y.Element("cp:category").Value ?? "none",
                                ContentStatus = y.Element("cp:contentStatus").Value ?? "none"
                            };


                    foreach (var m in x)
                    {
                        entities.Add("subject", m.Subject);
                        entities.Add("creator", m.Creator);
                        entities.Add("keywords", m.Keywords);
                        entities.Add("lastModifiedBy", m.LastModifiedBy);
                        entities.Add("revision", m.Revision);
                        entities.Add("created", m.Created);
                        entities.Add("modified", m.Modified);
                        entities.Add("category", m.Category);
                        entities.Add("contentStatus", m.ContentStatus);
                    }
                }

                package.Close();

                return true;
            }
            catch (Exception e)
            {
                eventLog.WritenewEvent(e.ToString());
                Console.WriteLine(e);
                return false;
            }
        }



        /// <summary>
        /// Extract the text of an OOXML or XPS file
        /// </summary>
        /// <param name="location">document location</param>
        /// <returns>bool state</returns>
        private bool GetText(string location)
        {
            try
            {
                // Load the OOXML or XPS document
                Package package = Package.Open(location, FileMode.Open, FileAccess.Read);
                // XMLdoc
                XmlDocument doc = new XmlDocument();

                foreach (PackagePart _part in package.GetParts())
                {
                    
                    doc.Load(_part.GetStream());
                    XmlNodeList list = doc.GetElementsByTagName("w:t");

                    foreach (XmlNode node in list)
                        if (!string.IsNullOrEmpty(node.InnerText))
                            documentText += " " + node.InnerText;

                    /*
                    XDocument xmldoc = XDocument.Load(XmlReader.Create(_part.GetStream()));

                    var x = from y in xmldoc.Elements()
                            select new
                            {
                                Content = (from e in y.Elements("w:t")
                                           select e.Value).ToList()
                            };

                    foreach (var m in x)
                    {
                        m.Content.ForEach(delegate(string i)
                        {
                            if (!string.IsNullOrEmpty(i))
                                documentText += " " + i;
                        });
                    }*/
                }
                package.Close();
                return true;
            }
            catch (Exception e)
            {
                eventLog.WritenewEvent(e.ToString());
                Console.WriteLine(e);

                return false;
            }
        }

        #endregion
    }
}
